    package com.xuecheng.content.service.impl;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.xuecheng.base.exception.CommonError;
    import com.xuecheng.base.exception.XueChengPlusException;
    import com.xuecheng.content.config.MultipartSupportConfig;
    import com.xuecheng.content.feignclient.MediaServiceClient;
    import com.xuecheng.content.mapper.CourseBaseMapper;
    import com.xuecheng.content.mapper.CourseMarketMapper;
    import com.xuecheng.content.mapper.CoursePublishMapper;
    import com.xuecheng.content.mapper.CoursePublishPreMapper;
    import com.xuecheng.content.model.dto.CourseBaseInfoDto;
    import com.xuecheng.content.model.dto.CoursePreviewDto;
    import com.xuecheng.content.model.dto.TeachplanDto;
    import com.xuecheng.content.model.po.CourseBase;
    import com.xuecheng.content.model.po.CourseMarket;
    import com.xuecheng.content.model.po.CoursePublish;
    import com.xuecheng.content.model.po.CoursePublishPre;
    import com.xuecheng.content.service.CourseBaseInfoService;
    import com.xuecheng.content.service.CoursePublishService;
    import com.xuecheng.content.service.TeachplanService;
    import com.xuecheng.messagesdk.model.po.MqMessage;
    import com.xuecheng.messagesdk.service.MqMessageService;
    import org.apache.commons.lang.StringUtils;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.springframework.beans.BeanUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
    import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

    import java.io.*;
    import java.time.LocalDateTime;
    import java.util.List;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;
    import org.apache.commons.io.IOUtils;

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Random;
    import java.util.concurrent.TimeUnit;

    /**
     * @author 陈竞超
     * @version 1.0
     * @qq 2250537249
     */
    @Service
    public class CoursePublishServiceImpl implements CoursePublishService {
        @Autowired
        CoursePublishService coursePublishService;
        @Autowired
        FreeMarkerConfigurer freeMarkerConfigurer;
        @Autowired
        CourseBaseInfoService courseBaseInfoService;
        @Autowired
        MediaServiceClient mediaServiceClient;
        @Autowired
        TeachplanService teachplanService;

        @Autowired
        CourseBaseMapper courseBaseMapper;

        @Autowired
        CourseMarketMapper courseMarketMapper;

        @Autowired
        CoursePublishPreMapper coursePublishPreMapper;
        @Autowired
        CoursePublishMapper coursePublishMapper;

        @Autowired
        MqMessageService mqMessageService;
        @Autowired
        RedisTemplate redisTemplate;
        @Autowired
        RedissonClient redissonClient;
        @Override
        public CoursePreviewDto getCoursePreviewInfo(Long courseId) {

            //课程基本信息、营销信息
            CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);

            //课程计划信息
            List<TeachplanDto> teachplanTree= teachplanService.findTeachPlanTree(courseId);

            CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
            coursePreviewDto.setCourseBase(courseBaseInfo);
            coursePreviewDto.setTeachplans(teachplanTree);
            return coursePreviewDto;
        }
        @Transactional
        @Override
        public void commitAudit(Long companyId, Long courseId) {

            //约束校验
            CourseBase courseBase = courseBaseMapper.selectById(courseId);
            //课程审核状态
            String auditStatus = courseBase.getAuditStatus();
            //当前审核状态为已提交不允许再次提交
            if("202003".equals(auditStatus)){
                XueChengPlusException.cast("当前为等待审核状态，审核完成可以再次提交。");
            }
            //本机构只允许提交本机构的课程
            if(!courseBase.getCompanyId().equals(companyId)){
                XueChengPlusException.cast("不允许提交其它机构的课程。");
            }

            //课程图片是否填写
            if(StringUtils.isEmpty(courseBase.getPic())){
                XueChengPlusException.cast("提交失败，请上传课程图片");
            }

            //添加课程预发布记录
            CoursePublishPre coursePublishPre = new CoursePublishPre();
            //课程基本信息加部分营销信息
            CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
            BeanUtils.copyProperties(courseBaseInfo,coursePublishPre);
            //课程营销信息
            CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
            //转为json
            String courseMarketJson = JSON.toJSONString(courseMarket);
            //将课程营销信息json数据放入课程预发布表
            coursePublishPre.setMarket(courseMarketJson);

            //查询课程计划信息
            List<TeachplanDto> teachplanTree = teachplanService.findTeachPlanTree(courseId);
            if(teachplanTree.size()<=0){
                XueChengPlusException.cast("提交失败，还没有添加课程计划");
            }
            //转json
            String teachplanTreeString = JSON.toJSONString(teachplanTree);
            coursePublishPre.setTeachplan(teachplanTreeString);

            //设置预发布记录状态,已提交
            coursePublishPre.setStatus("202003");
            //教学机构id
            coursePublishPre.setCompanyId(companyId);
            //提交时间
            coursePublishPre.setCreateDate(LocalDateTime.now());
            CoursePublishPre coursePublishPreUpdate = coursePublishPreMapper.selectById(courseId);
            if(coursePublishPreUpdate == null){
                //添加课程预发布记录
                coursePublishPreMapper.insert(coursePublishPre);
            }else{
                coursePublishPreMapper.updateById(coursePublishPre);
            }

            //更新课程基本表的审核状态
            courseBase.setAuditStatus("202003");
            courseBaseMapper.updateById(courseBase);
        }

        @Transactional
        @Override
        public void publish(Long companyId, Long courseId) {

            //约束校验
            //查询课程预发布表
            CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
            if(coursePublishPre == null){
                XueChengPlusException.cast("请先提交课程审核，审核通过才可以发布");
            }
            //本机构只允许提交本机构的课程
            if(!coursePublishPre.getCompanyId().equals(companyId)){
                XueChengPlusException.cast("不允许提交其它机构的课程。");
            }


            //课程审核状态
            String auditStatus = coursePublishPre.getStatus();
            //审核通过方可发布
            if(!"202004".equals(auditStatus)){
                XueChengPlusException.cast("操作失败，课程审核通过方可发布。");
            }

            //保存课程发布信息
            saveCoursePublish(courseId);

            //保存消息表
            saveCoursePublishMessage(courseId);

            //删除课程预发布表对应记录
            coursePublishPreMapper.deleteById(courseId);

        }

        @Override
        public File generateCourseHtml(Long courseId) throws IOException, TemplateException {
            File htmlFile = null;
            try {
                //加载模板
                //选指定模板路径,classpath下templates下
                //得到classpath路径
    //        String classpath = this.getClass().getResource("/").getPath();
    //        configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));
    //
    //        //设置字符编码
    //        configuration.setDefaultEncoding("utf-8");
    //
    //        //指定模板文件名称
    //        Template template = configuration.getTemplate("course_template.ftl");
                Template template = freeMarkerConfigurer.getConfiguration().getTemplate("course_template.ftl");
                //准备数据
                CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(courseId);

                Map<String, Object> map = new HashMap<>();
                map.put("model", coursePreviewInfo);

                //静态化
                //参数1：模板，参数2：数据模型
                String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
                System.out.println(content);
                //将静态化内容输出到文件中
                InputStream inputStream = IOUtils.toInputStream(content);
                htmlFile = File.createTempFile("coursepublish",".html");
                //输出流
                FileOutputStream outputStream = new FileOutputStream(htmlFile);
                IOUtils.copy(inputStream, outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TemplateException e) {
                e.printStackTrace();
            }
            return htmlFile;
        }


        @Override
        public void uploadCourseHtml(Long courseId, File file) {
            try {
                MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
                String upload = mediaServiceClient.uploadFile(multipartFile, "course/" + courseId + ".html");
                if (upload==null){
                    XueChengPlusException.cast("上传文件有误");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public CoursePublish getCoursePublish(Long courseId) {
            CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
            return coursePublish ;
        }

//        @Override
//        public CoursePublish getCoursePublishCache(Long courseId) {
//            //从缓存中查询
//            Object jsonObj = redisTemplate.opsForValue().get("course" + courseId);
//            //缓存中有
//            if (jsonObj!=null){
//                //缓存中有，直接返回数据
//                String s = jsonObj.toString();
//                if ("null".equals(jsonObj)){
//                    return null;
//                }
//                CoursePublish coursePublish = JSON.parseObject(s, CoursePublish.class);
//                return  coursePublish;
//            }else {
//                //从数据库查询
//                CoursePublish coursePublish = getCoursePublish(courseId);
////                if (coursePublish!=null){
//                    redisTemplate.opsForValue().set("course"+courseId,JSON.toJSONString(coursePublish),30+new Random().nextInt(100), TimeUnit.SECONDS);
////                }
//                return coursePublish;
//            }
//        }
//        @Override
//        public  CoursePublish getCoursePublishCache(Long courseId){
//
//                //查询缓存
//                String jsonString = (String) redisTemplate.opsForValue().get("course:" + courseId);
//                if(StringUtils.isNotEmpty(jsonString)){
//                    if(jsonString.equals("null"))
//                        return null;
//                    CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class);
//                    return coursePublish;
//                }else{
//                    synchronized(this){
//                        Object o = redisTemplate.opsForValue().get("course:" + courseId);
//                        if(o!=null) {
//                            String s = o.toString();
//                            if(s.equals("null"))
//                                return null;
//                            CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class);
//                            return coursePublish;
//                        }
//                    System.out.println("=========从数据库查询==========");
//                    //从数据库查询
//                    CoursePublish coursePublish = getCoursePublish(courseId);
//                    //设置过期时间300秒
//                    redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish),300, TimeUnit.SECONDS);
//                    return coursePublish;
//                }
//            }
//
//        }
        @Override
        public  CoursePublish getCoursePublishCache(Long courseId) {
            Object jsonObj = redisTemplate.opsForValue().get("course" + courseId);
            //缓存中有
            if (jsonObj!=null){
                //缓存中有，直接返回数据
                String s = jsonObj.toString();
                if ("null".equals(jsonObj)){
                    return null;
                }
                CoursePublish coursePublish = JSON.parseObject(s, CoursePublish.class);
                return  coursePublish;
            }else{
                //每门课程设置一个锁
                RLock lock = redissonClient.getLock("coursequerylock:"+courseId);
                //获取锁
                lock.lock();
                try {
                    String jsonString = (String) redisTemplate.opsForValue().get("course:" + courseId);
                    if(StringUtils.isNotEmpty(jsonString)){
                        CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class);
                        return coursePublish;
                    }
                    System.out.println("=========从数据库查询==========");
//                    try {
//                        Thread.sleep(30000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }

                    //从数据库查询
                    CoursePublish coursePublish = getCoursePublish(courseId);
                    redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish),1,TimeUnit.DAYS);
                    return coursePublish;
                }finally {
                    //释放锁
                    lock.unlock();
                }
            }
        }
        /**
     * @description 保存课程发布信息
     * @param courseId  课程id
     * @return void
     * @author Mr.M
     * @date 2022/9/20 16:32
     */
    private void saveCoursePublish(Long courseId){
        //整合课程发布信息
        //查询课程预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if(coursePublishPre == null){
            XueChengPlusException.cast("课程预发布数据为空");
        }
        String status = coursePublishPre.getStatus();
        if (!status.equals("202004")){
            XueChengPlusException.cast("课程没有审核通过");
        }
        CoursePublish coursePublish = new CoursePublish();

        //拷贝到课程发布对象
        BeanUtils.copyProperties(coursePublishPre,coursePublish);
        coursePublish.setStatus("203002");
        CoursePublish coursePublishUpdate = coursePublishMapper.selectById(courseId);
        if(coursePublishUpdate == null){
            coursePublishMapper.insert(coursePublish);
        }else{
            coursePublishMapper.updateById(coursePublish);
        }
        //更新课程基本表的发布状态
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setStatus("203002");
        courseBaseMapper.updateById(courseBase);
        saveCoursePublishMessage(courseId);
        coursePublishPreMapper.deleteById(courseId);
    }

    /**
     * @description 保存消息表记录，稍后实现
     * @param courseId  课程id
     * @return void
     * @author Mr.M
     * @date 2022/9/20 16:32
     */
    private void saveCoursePublishMessage(Long courseId){
        MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if(mqMessage==null){
            XueChengPlusException.cast(CommonError.UNKOWN_ERROR);
        }
    }



}
